﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace AutomatedDecisionMaking.Class.Algorithms
{
    class MOWminAlgorithm
    {
        private readonly DecisionMatrix _mDecisionMatrix;       /// Macierz decyzji
        private List<double> _mScenarioWeights;                 /// Wagi poszczególnych scenariuszy
        private readonly List<double> _mMaxInRowValues;         /// Maksymalna wartość w wierszu
        private readonly List<string> _mStrMaxInRowValues;      /// Lista nawiększych wartości w poszczególnych rzędach w odpowiednim formacie strign
        private readonly List<List<double>> _mRegretMatrix;     /// Macierz żalu
        private readonly List<double> _mWeightedValues;         /// Lista maksymalnych wartości z poszczególnych wierszy macierzy żalu
        private readonly List<string> _mStrWeightedValues;      /// Lista maksymalnych wartości z poszczególnych wierszy macierzy żalu w formacie STRING
        private double _mMinWeightedVal;                        /// Minimalna wartość z pośród maksymalnych
        private string _mDecision;                              /// Podjęta decyzja

        /// <summary>
        /// Konstruktor algorytmu realizującego kryterium najmniejszego oczekiwanego żalu.
        /// </summary>
        /// <param name="decisionMatrix">Macierz decyzji wprowadzona porzez użytkownika</param>
        public MOWminAlgorithm(DecisionMatrix decisionMatrix)
        {
            _mScenarioWeights = new List<double>();
            _mMaxInRowValues = new List<double>();
            _mStrMaxInRowValues = new List<string>();
            _mRegretMatrix = new List<List<double>>();
            _mWeightedValues = new List<double>();
            _mStrWeightedValues = new List<string>();
            _mDecisionMatrix = decisionMatrix;
        }

        /// <summary>
        /// Reset całego algorytmu
        /// </summary>
        public void Reset()
        {
            _mScenarioWeights.Clear();
            _mMaxInRowValues.Clear();
            _mStrMaxInRowValues.Clear();
            _mRegretMatrix.Clear();
            _mWeightedValues.Clear();
            _mStrWeightedValues.Clear();
        }

        /// <summary>
        /// Uruchomienie algorytmu i rozwiązanie postawionego zadania
        /// </summary>
        public void CalculateSolution()
        {
            CalculateRegretMatrix();

            for (int i = 0; i < _mRegretMatrix.Count; ++i)
            {
                string element = _mDecisionMatrix.DecisionList.ElementAt(i);
                double weightedVal = 0;
                var regretRow = _mRegretMatrix[i];
                for (int j = 0; j < regretRow.Count; ++j)
                    weightedVal += regretRow[j]*_mScenarioWeights[j];

                _mStrWeightedValues.Add(element + " : wartość ważona = " + weightedVal);
                _mWeightedValues.Add(weightedVal);

                /*double maxVal = m_DecisionMatrix.Value[i].Max();
                m_StrMaxInRowValues.Add(element + " : max = "+ maxVal);
                m_MaxInRowValues.Add(maxVal);*/


            }
            _mMinWeightedVal = _mWeightedValues.Min();
            _mDecision = _mDecisionMatrix.DecisionList.ElementAt(_mWeightedValues.FindIndex(w => w == _mMinWeightedVal));
        }

        /// <summary>
        /// Ustawienie wag dla poszczególnych scenariuszy
        /// </summary>
        /// <param name="weights">Wagi dla scenariuszy</param>
        public void SetWeights(List<double> weights)
        {
            _mScenarioWeights = weights;
        }

        /// <summary>
        /// Pobranie wag dla poszczególnych scenariuszy
        /// </summary>
        /// <returns>Wagi dla scenariuszy</returns>
        public List<double> GetWeights()
        {
            return _mScenarioWeights;
        }

        /// <summary>
        /// Pobranie podjętej decyzji
        /// </summary>
        /// <returns>Podjęta decyzja</returns>
        public string GetDecision()
        {
            return _mDecision;
        }

        /// <summary>
        /// Dostęp do najmniejszej wartości ważonej z pośród wszystkich
        /// </summary>
        /// <returns>Najmniejsza wartość ważona</returns>
        public double GetMinWeightedValue()
        {
            return _mMinWeightedVal;
        }

        /// <summary>
        /// Dostęp do wszystkich wartości wazonych w formacie string
        /// </summary>
        /// <returns>Wartości ważone</returns>
        public List<string> GetWeightedValuesStr()
        {
            return _mStrWeightedValues;
        }

        /// <summary>
        /// Dostęp do wszystkich wartości wazonych w formacie
        /// </summary>
        /// <returns>Wartości ważone</returns>
        public List<double> GetWeightedValues()
        {
            return _mWeightedValues;
        }

        /// <summary>
        /// Dostęp do macierzy żalu
        /// </summary>
        /// <returns>Macierz żalu</returns>
        public List<List<double>> GetRegretMatrix()
        {
            return _mRegretMatrix;
        }  // Macierz żalu

        /// <summary>
        /// Dostęp do największych wartości w rzędach dla macierzy decyzji.
        /// </summary>
        /// <returns>Największe wartości w rzędach</returns>
        public List<string> GetMaxInRowsStr()
        {
            return _mStrMaxInRowValues;
        }

        /// <summary>
        /// Dostęp do macierzy decyzji jaka jest podawana przez użytkownika
        /// </summary>
        /// <returns>Macierz decyzji</returns>
        public DecisionMatrix GetDecisionMatrix()
        {
            return _mDecisionMatrix;
        }
  
        /// <summary>
        /// Wyznaczenie macierzy żalu
        /// </summary>
        private void CalculateRegretMatrix()
        {
            int decisionNo = _mDecisionMatrix.DecisionList.Count;
            for(int i=0; i<decisionNo; ++i)
            {
                var decisionRow = _mDecisionMatrix.Value[i];
                _mMaxInRowValues.Add(decisionRow.Max());

                string element = _mDecisionMatrix.DecisionList.ElementAt(i);
                _mStrMaxInRowValues.Add(element + " : max = " + decisionRow.Max());
                _mRegretMatrix.Add(decisionRow.ConvertAll(w => Math.Abs(w - _mMaxInRowValues[i])));
            }
        }
    }
}
